Kapitel 24 Programmiertechniken
24.1 Drag & Drop-Operationen  
Drag & Drop gehört zu den fundamentalen Techniken der Windows-Betriebssysteme. Damit wird es einem Anwender ermöglicht, ein Objekt zu markieren und es bei gedrückter Maustaste an eine andere Stelle zu ziehen. Der Empfänger kann sich sowohl in derselben als auch in einer anderen Anwendung befinden. Unterstützend erhält der Anwender während des Ziehvorgangs ein visuelles Feedback, wenn sich der Mauszeiger über einer Komponente befindet, die in der Lage ist, das gezogene Objekt aufzunehmen. Diese Technik wird beispielsweise im Windows-Explorer sehr gerne dazu benutzt, eine oder mehrere Dateien in ein anderes Verzeichnis zu verschieben oder zu kopieren.
Bei Drag & Drop-Vorgängen spielen immer zwei Elemente eine Rolle: die Quelle, aus der ein Objekt gezogen wird, und der Empfänger, der das Objekt entgegennimmt. Beim Kopieren erhält der Empfänger eine Kopie des Objekts, beim Verschieben wird das Objekt in der Quelle gelöscht, und bei einer Verknüpfungsoperation verweisen sowohl Quelle als auch Ziel auf dasselbe Objekt.
In Abhängigkeit vom Status der Umschalttasten wird entschieden, ob eine Operation ein Objekt kopiert, verschiebt oder auch nur verknüpft. Wird keine Taste gedrückt, handelt es sich üblicherweise um eine Verschiebeoperation, ist die (Strg)-Taste während des Vorgangs gedrückt, wird kopiert, und die Kombination aus (ª)- und (Strg)-Taste bewirkt das Verknüpfen.
24.1.1 Der Ablauf einer Drag & Drop-Operation  
Normalerweise werden Drag & Drop-Operationen als Reaktion auf das MouseDown-Ereignis ausgelöst. Meistens handelt es sich dabei um die linke Maustaste, in manchen Anwendungen sind aber auch Operationen über die rechte möglich. Um eine Drag & Drop-Operation einzuleiten, wird im Ereignishandler die Methode DoDragDrop des Startelements aufgerufen.
Nicht jede Komponente ist automatisch ein potenzieller Empfänger der Drag & Drop-Operation. Vielmehr müssen die Komponenten, die als Empfänger in Frage kommen, die Eigenschaft AllowDrop=True eingestellt haben.
In Verbindung mit dem Ziehvorgang treten mehrere Ereignisse auf. Die beiden wichtigsten sind DragEnter und DragDrop. Da mit Drag & Drop die verschiedensten Datenformate bewegt werden können (Zeichenfolgen, Dateien, Images usw.), muss jeder potenzielle Empfänger einer Drag & Drop-Operation überprüfen, ob er das aktuell gezogene Datenformat überhaupt aufnehmen kann. Das passiert im Ereignis DragEnter. Das Ablegen des gezogenen Objekts erfolgt dann im Ereignis DragDrop.
24.1.2 Das Einleiten einer Drag & Drop-Operation  
Um die Drag & Drop-Operation auszulösen, ist der Aufruf der Methode DoDragDrop notwendig, der im ersten Parameter das zu kopierende oder zu verschiebende Objekt übergeben wird. Der zweite Parameter vom Typ DragDropEffects beschreibt, welche Operationen mit dem Objekt möglich sind.
| Public Function DoDragDrop(Object, DragDropEffects) As DragDropEffects
|
Die Methode befindet sich so lange in der Ausführung, bis die Operation abgeschlossen ist. Der Rückgabewert der Methode beschreibt, wie der Empfänger die Daten entgegengenommen hat. In den meisten Fällen werden Sie aber den Rückgabewert vermutlich ignorieren können.
Die Mitglieder der Enumeration DragDropEffects können bitweise verknüpft werden, um mit einem Methodenaufruf mehrere verschiedene Operationen zu erlauben.
Tabelle 24.1 Die Enumeration »DragDropEffects«
| Mitglied
|
Beschreibung
|
| None
|
Die Daten werden vom Ziel nicht akzeptiert.
|
| Copy
|
Die Daten werden in das Ziel kopiert.
|
| Move
|
Die Daten aus der Quelle werden in das Ziel verschoben.
|
| Link
|
Die Daten aus der Quelle werden mit dem Ziel verknüpft.
|
| Scroll
|
Der Bildlauf wird begonnen oder momentan im Ziel durchgeführt.
|
| All
|
Die Daten werden kopiert, aus der Quelle entfernt und über einen Bildlauf im Ablageziel abgelegt.
|
So einfach im ersten Moment das Einleiten einer Drag & Drop-Operation erscheinen mag, so schwierig kann es sich bei der Programmierung erweisen. Der Grund dafür ist, dass einige Steuerelemente bei einem Click-Ereignis eine Standardreaktion zeigen. Die Problematik ist, zwischen dem Standardverhalten und der Drag & Drop-Operation zu unterscheiden.
24.1.3 Die Ereignisse des Empfängers einer Drag & Drop-Operation  
Der Empfänger muss auch als ein solcher konfiguriert sein, standardmäßig ist das nämlich nicht der Fall. Ein Drag & Drop-Empfänger wird erst zu einem solchen, wenn die von der Klasse Control geerbte Eigenschaft AllowDrop auf True festgelegt ist und die Komponente damit ihre Empfangsbereitschaft signalisiert.
| Public Overridable Property AllowDrop As Boolean
|
Bei einer als Empfänger registrierten Komponente spielen insgesamt vier Ereignisse eine Rolle: DragEnter, DragOver, DragDrop und DragLeave.
| Public Event DragEnter As DragEventHandler
|
| Public Event DragOver As DragEventHandler
|
| Public Event DragDrop As DragEventHandler
|
| Public Event DragLeave As EventHandler
|
Machen wir uns zunächst deutlich, unter welchen Umständen die Ereignisse ausgelöst werden.
|
Das Ereignis DragEnter wird ausgelöst, wenn der Mauszeiger in den Bereich eines Drag & Drop-Empfängers eindringt. Dabei kann es sich um eine Form oder um ein Steuerelement handeln. Das Ereignis wird dazu benutzt, um zu prüfen, ob das betreffende Steuerelement in der Lage ist, das Datenformat des gezogenen Objekts aufzunehmen. Ist das nicht der Fall, wird ein Symbol angezeigt, das an ein Verbotsschild erinnert. Dieses Symbol hat noch eine weiterreichende Konsequenz. Solange nämlich dieses Symbol angezeigt wird, tritt auch kein DragDrop-Ereignis auf, wenn der Anwender die Maustaste loslässt. Die Daten werden dann nicht fallen gelassen. |
|
DragOver ist mit dem Ereignis MouseOver vergleichbar und tritt kontinuierlich auf, während die Maus über die Komponente bewegt wird. Dabei wird die Darstellung des Cursors abhängig davon, ob es sich um einen Verschiebe- oder Kopiervorgang handelt, geändert. Im Windows-Explorer beispielsweise wird der Cursor bei einer Verschiebeoperation durch einen Pfeil gekennzeichnet, beim Kopieren durch ein zusätzliches »+«-Zeichen am rechten unteren Ende des Pfeils. Über einem Element, das kein Empfänger einer Drag & Drop-Operation ist, wird sich der Mauszeiger nicht ändern und stattdessen einen Kreis mit dem schrägen roten Balken anzeigen. |
|
Wird die gedrückte Maustaste über dem Empfänger losgelassen, kommt es zum DragDrop-Ereignis, und das Objekt wird abgelegt. Wie das losgelassene Objekt im Empfänger behandelt wird, hängt von den Anforderungen ab. |
|
Wird mit gedrückter Maustaste der Bereich eines möglichen Empfängers verlassen, wird dessen Ereignis DragLeave ausgelöst. Nur in wenigen Fällen werden Sie einen Ereignishandler benötigen, um beim Verlassen des Empfängers eine Operation auszuführen. |
Die Parameterliste der Ereignishandler
Das Ereignis DragLeave wird von einem EventArgs-Objekt begleitet, das uns schon oft begegnet ist und von dem wir wissen, dass es keine ereignisrelevanten Daten liefert. Daher können wir auf eine weitergehende Beschreibung verzichten.
Anders sieht es bei den drei Ereignissen DragEnter, DragDrop und DragOver aus. Die Ereignishandler dieser Ereignisse empfangen ein Objekt vom DragEventArgs, das eine Reihe von Eigenschaften bereitstellt, um genauere und verwertbare Informationen über die laufende Operation zu liefern.
Tabelle 24.2 Eigenschaften des »DragEventArgs«-Objekts
| Eigenschaft
|
Beschreibung
|
| AllowEffected
|
Diese Eigenschaft ist schreibgeschützt und beschreibt die Optionen, die dem Empfänger von der Quelle zur Verfügung gestellt werden (Kopieren, Verschieben oder Verknüpfen). Damit enthält diese Eigenschaft die Kombination von DragDropEffects, die beim Aufruf der Methode DoDragDrop dem zweiten Parameter übergeben worden sind.
|
| Data
|
Enthält die dem Ereignis zugeordneten Daten. Die Daten sind vom Typ IDataObject.
|
| Effect
|
Diese Eigenschaft, die ebenfalls vom Typ DragDropEffects ist, legt die Optionen des Drag & Drop-Vorgangs und somit auch das Aussehen der Maus für den Empfänger fest. Effect muss insbesondere im Ereignishandler von DragEnter eingestellt werden, da ansonsten ein Mauscursor dargestellt wird, der symbolisiert, dass kein DragDrop-Ereignis ausgelöst wird. Eingestellt werden dürfen aber nur Werte, die auch unter AllowEffected angegeben sind.
|
| KeyState
|
Ruft den aktuellen Zustand von (ª), (Strg), (Alt) sowie den Zustand der Maustasten ab (siehe auch Tabelle 24.3).
|
| X, Y
|
Ruft die x- bzw. y-Koordinate des Mauszeigers in Bildschirmkoordinaten ab.
|
| Hinweis
|
|
Die gezogenen Daten liegen während einer Drag & Drop-Operation im Format IDataObject vor. Diesen Typ mit seinen Methoden wie beispielsweise GetDataPresent und GetFormats hatten wir im Zusammenhang mit der Programmierung der Zwischenablage in Abschnitt 18.4 bereits besprochen.
|
Beachten Sie bitte, dass X und Y die Koordinaten des Mauszeigers auf dem Bildschirm liefern. Diese Werte sind normalerweise wertlos, können aber relativ einfach in die Koordinaten eines Steuerelements umgerechnet werden. Dabei hilft die PointToClient-Methode weiter, die auf das erforderliche Steuerelement aufgerufen wird:
| Dim pt As Point = Steuerelement.PointToClient(Me.MousePosition)
|
Die Eigenschaft KeyState ist folgendermaßen definiert:
| Public ReadOnly Property KeyState As Integer
|
Diese Eigenschaft verwendet erstaunlicherweise nicht wie ansonsten üblich eine Enumeration, sondern beschreibt den Zustand aller in Frage kommenden Tasten über einen Integer. Da KeyState mit dem Flags-Attribut verknüpft ist, wird der Rückgabewert der Eigenschaft bitweise interpretiert.
Tabelle 24.3 Die Bitflags der Eigenschaft »KeyState«
| Bitflag
|
Taste
|
| 1
|
linke Maustaste
|
| 2
|
rechte Maustaste
|
| 4
|
(Shift)-Taste
|
| 8
|
(Strg)-Taste
|
| 16
|
mittlere Maustaste
|
| 32
|
(Alt)-Taste
|
Das »QueryContinueDrag«-Ereignis der Ereignisquelle
Für das Steuerelement, das für die Drag & Drop-Operation als Quelle verantwortlich ist, werden permanent die QueryContinueDrag-Ereignisse ausgelöst. Das Ereignis bietet sich insbesondere an, um einen eingeleiteten Vorgang vorzeitig abzubrechen und dabei festzulegen, was mit dem gezogenen Objekt passieren soll.
Das Ereignis schickt an seinen Ereignishandler ein Objekt vom Typ QueryContinueDrag-EventArgs. Dieses hat drei Eigenschaften:
|
Action |
|
EscapePressed |
|
KeyState |
KeyState teilt mit, welche Tasten der Operation gedrückt sind (siehe Tabelle 24.3), EscapePressed ruft ab, ob der Anwender die (ESC)-Taste gedrückt hat.
Mit Action lässt sich der Status der andauernden Operation bestimmen und beeinflussen. Diese Eigenschaft ist vom Typ der Enumeration DragAction, mit welcher der Fortgang der Operation festgelegt werden kann.
Tabelle 24.4 Die Enumeration »DragAction«
| Member
|
Beschreibung
|
| Cancel
|
Die Operation wird abgebrochen. Dabei werden die Daten nicht abgelegt.
|
| Continue
|
Die Operation wird fortgesetzt.
|
| Drop
|
Die Operation wird beendet. Dabei werden die Daten abgelegt.
|
24.1.4 Programmbeispiele  
An den folgenden vier Beispielen wollen wir uns nun ansehen, wie Drag & Drop realisiert werden kann. Im ersten Beispiel wird nur eine einfache Operation zwischen zwei Textboxen gezeigt, im zweiten eine Operation, bei der zwischen zwei Pictureboxen ein Bildchen hin- und hergeschoben/kopiert wird. Drag & Drop zwischen zwei Listboxen ist nur unter erheblichem Programmieraufwand möglich, wenn die Listboxen eine Mehrfachauswahl zulassen. Das dritte Beispiel stellt dazu eine gleichwertige Alternative vor, die anstelle von Listboxen ListView-Steuerelemente benutzt. Im letzten Beispiel wird Ihnen abschließend noch gezeigt, wie Dateien bei einer Drag & Drop-Operation behandelt werden.
Drag & Drop zwischen zwei Textboxen
Die Form des folgenden Beispiels enthält die beiden Textboxen textBox1 und textBox2. Der Inhalt von textBox1 soll mittels Drag & Drop in die textBox2 verschoben oder kopiert werden. Zum Kopieren muss während des Ziehvorgangs die (Strg)-Taste gedrückt sein. Die Eigenschaft AllowDrop von textBox2 ist auf True eingestellt.
| ' ----------------------------------------------------------
|
| ' Beispiel: ...\Kapitel 24\DragAndDrop_Textboxen
|
| ' ----------------------------------------------------------
|
| Public Class Form1
|
| Private Sub TextBox2_DragEnter(ByVal sender AsObject, _
|
| ByVal e As DragEventArgs) Handles TextBox2.DragEnter
|
| If e.Data.GetDataPresent(DataFormats.Text) Then
|
| ' wenn die Strg-Taste gedrückt ist
|
| If (e.KeyState And 8) = 8 Then
|
| e.Effect = DragDropEffects.Copy
|
| ' wenn nur die linke Maustaste gedrückt ist
|
| Else
|
| e.Effect = DragDropEffects.Move
|
| End If
|
| Else
|
| e.Effect = DragDropEffects.None
|
| End If
|
| End Sub
|
| Private Sub TextBox2_DragDrop(ByVal sender As Object, _
|
| ByVal e As DragEventArgs) Handles TextBox2.DragDrop
|
| TextBox2.Text = e.Data.GetData(DataFormats.Text)
|
| If (e.KeyState And 8) <> 8 Then
|
| TextBox1.Clear()
|
| End If
|
| End Sub
|
| Private Sub TextBox1_MouseDown(ByVal sender As Object, _
|
| ByVal e As MouseEventArgs) Handles TextBox1.MouseDown
|
| TextBox1.DoDragDrop(TextBox1.Text, _
|
| DragDropEffects.Copy Or DragDropEffects.Move)
|
| End Sub
|
| End Class
|
Eingeleitet wird die Drag & Drop-Operation mit dem Drücken der linken Maustaste im Textfeld textBox1. Dabei wird die Methode DoDragDrop aufgerufen, der im ersten Argument die zu erfassenden Daten mitgeteilt werden. Hier ist es der gesamte Inhalt von textBox1. Im zweiten Argument ist festgelegt, dass die Daten sowohl verschoben als auch kopiert werden können.
| textBox1.DoDragDrop(textBox1.Text,
|
| DragDropEffects.Copy Or DragDropEffects.Move)
|
Dringt der Mauszeiger bei gleichzeitig gedrückter linker Maustaste in den Bereich des Objekts textBox2 ein, wird das Ereignis DragEnter ausgelöst. Wir benutzen den Ereignishandler dazu, um zunächst einmal festzustellen, ob die von der aktuellen Drag & Drop-Operation erfassten Daten auch im Textformat vorliegen. Theoretisch wäre es auch möglich, dass aus einer anderen Quelle heraus Daten verschoben werden, die nicht im Text-, sondern zum Beispiel im Bildformat vorliegen. Dann darf die Textbox natürlich auch nicht mit einem Symbol ihre Bereitschaft signalisieren, die Daten aufnehmen zu können.
Verläuft die Überprüfung in DragEnter mit
| If e.Data.GetDataPresent(DataFormats.Text) Then
|
positiv, gilt es festzustellen, ob die (Strg)-Taste gedrückt ist oder nicht. Ist diese Zustandstaste gedrückt, werden die Daten – falls sie in der Textbox textBox2 fallen gelassen werden – kopiert, andernfalls nur verschoben. Das dazugehörige Symbol wird durch die Übergabe einer DragDropEffects-Konstanten an die Eigenschaft Effects festgelegt, beispielsweise:
| If (e.KeyState And 8) = 8 Then
|
| e.Effect = DragDropEffects.Copy
|
|
Die Zuweisung an Effect hat noch einen weiteren, sehr wichtigen Hintergrund, der zu erkennen ist, wenn man den Code in DragEnter auskommentiert: Es ist dann keine Drop-Operation mehr möglich. Als Symbol wird in diesem Fall nur noch ein Kreis mit einem schrägen Balken angezeigt. In DragEnter wird also folglich die Bereitschaft der Komponente festgelegt, die Daten zu empfangen, und darüber hinaus auch, wie die Daten behandelt werden.
|
Wird die Maustaste losgelassen, während sich der Mauszeiger über textBox2 befindet, kommt es zum Ereignis DragDrop. Hier werden die Daten nach vorhergehender Konvertierung in den Typ String in das Objekt textBox2 geschrieben. Außerdem muss überprüft werden, ob es sich um eine Verschiebe- oder Kopieroperation handelt. Im ersteren Fall gilt es, die verschobenen Daten in der Quelle zu löschen.
Da Drag & Drop auch anwendungsübergreifend funktioniert, können Sie aus einem beliebigen textbasierten Dokument heraus Daten verschieben. Andererseits wird das Verschieben beispielsweise einer Bitmap-Datei von der Textbox im Beispielprogramm ignoriert.
Drag & Drop zwischen zwei Pictureboxen
Genauso einfach wie das Verschieben einer Zeichenfolge ist das Verschieben eines Bildes. Der Code unterscheidet sich nur geringfügig, da nur der abweichende Datentyp zu beachten ist.
Im folgenden Beispiel enthält die Form zwei Pictureboxen. Nach dem Start enthält die mit pic1 bezeichnete Picturebox ein Bild, das in die mit pic2 bezeichnete Picturebox entweder verschoben oder kopiert werden kann. Weil es nur geringfügig mehr Codierungsaufwand bedeutet, ist in diesem Beispiel die Drag & Drop-Operation in beide Richtungen möglich. Dazu werden die Ereignisse MouseDown, DragEnter und DragDrop mit dem gleichen Ereignishandler verknüpft. Im DragDrop-Ereignishandler ist für den Fall, dass eine Verschiebeoperation vorliegt, in der richtigen Quelle das Bild zu löschen. Dazu ist die Referenz des sender-Parameters zu überprüfen.
| Hinweis
|
|
Die Eigenschaft AllowDrop der Pictureboxen muss natürlich auf True gesetzt werden. Im Eigenschaftsfenster wird diese Eigenschaft aber aus unerklärlichen Gründen nicht aufgelistet. Sie müssen also eine entsprechende Anweisung codieren. Dabei werden Sie feststellen, dass AllowDrop auch nicht in der IntelliSense-Liste zu finden ist. Setzen Sie sich darüber einfach hinweg.
|
| ' ---------------------------------------------------------
|
| ' Beispiel: ...\Kapitel 24\DragAndDrop_Bilddateien
|
| ' ---------------------------------------------------------
|
| Public Class Form1
|
| Private Sub Form1_Load(...) Handles MyBase.Load
|
| pic1.AllowDrop = True
|
| pic2.AllowDrop = True
|
| End Sub
|
| Private Sub pic_MouseDown(...) Handles pic2.MouseDown, _
|
| pic1.MouseDown
|
| Dim pic As PictureBox = sender
|
| ' wenn ein Bild angezeigt wird, die Drag&Drop-Operation einleiten
|
| If pic.Image IsNot Nothing Then
|
| pic.DoDragDrop(pic.Image, _
|
| DragDropEffects.Copy Or DragDropEffects.Move)
|
| End If
|
| End Sub
|
| Private Sub pic_DragEnter(ByVal sender As Object, _
|
| ByVal e As DragEventArgs) Handles pic2.DragEnter, _
|
| pic1.DragEnter
|
| If e.Data.GetDataPresent(DataFormats.Bitmap) Then
|
| ' wenn die Strg-Taste gedrückt ist
|
| If (e.KeyState And 8) = 8 Then
|
| e.Effect = DragDropEffects.Copy
|
| ' wenn nur die linke Maustaste gedrückt ist
|
| Else
|
| e.Effect = DragDropEffects.Move
|
| End If
|
| Else
|
| e.Effect = DragDropEffects.None
|
| End If
|
| End Sub
|
| Private Sub pic_DragDrop(ByVal sender As Object, _
|
| ByVal e As DragEventArgs) Handles pic2.DragDrop, _
|
| pic1.DragDrop
|
| Dim pic As PictureBox = sender
|
| ' die empfangenen Daten in den Typ Image konvertieren
|
| pic.Image = e.Data.GetData(DataFormats.Bitmap)
|
| If (e.KeyState And 8) <> 8 Then
|
| If (pic Is pic1) Then
|
| pic2.Image = Nothing
|
| Else
|
| pic1.Image = Nothing
|
| End If
|
| End If
|
| End Sub
|
| End Class
|
Drag & Drop zwischen Listen
Wenn Sie die Elemente zwischen zwei Listen mit Drag & Drop verschieben oder kopieren wollen, wird es etwas schwieriger. Normalerweise werden Sie sich bei einer Liste für den Typ ListBox entscheiden, der jedoch Probleme bereitet, wenn mehrere Listenelemente an der Operation teilnehmen sollen. In solchen Fällen ist der Typ ListView empfehlenswerter.
Das Steuerelement ListView hat, ebenso wie auch TreeView, ein zusätzliches Ereignis, mit dem das Ziehen eines oder mehrerer Elemente erleichtert wird: ItemDrag. Dieses Ereignis tritt auf, wenn zur Laufzeit mit dem Ziehen begonnen wird. Über die Eigenschaften des Args-Parameters kann man die bei dem Vorgang gedrückte Maustaste sowie das zu ziehende Element ermitteln, aber meistens wird der Ereignishandler nur dazu benutzt, die Methode DoDragDrop aufzurufen.
Im folgenden Beispielprogramm können die Listenelemente von zwei ListView-Objekten beliebig verschoben werden. Die Form enthält zwei dieser Steuerelemente, deren AllowDrop-Eigenschaft selbstverständlich wieder auf True gesetzt ist. Da standardmäßig nur eine einfache Auswahl möglich ist, sollte die Mehrfachauswahl mit der Eigenschaft MultiSelect eingestellt werden. Um die Listbox zu simulieren, ist View=List gewählt, aber es kann natürlich auch aus den anderen angebotenen Ansichten heraus verschoben werden.
Sehen wir uns zuerst den Code des ItemDrag-Ereignishandlers an, der mit beiden Listenansichten verknüpft ist.
| Private Sub ListView_ItemDrag(ByVal sender As Object, _
|
| ByVal e As ItemDragEventArgs) _
|
| Handles ListView2.ItemDrag, ListView1.ItemDrag
|
| Dim listview As ListView = sender
|
| Dim items(listview.SelectedItems.Count – 1) As ListViewItem
|
| For i As Integer = 0 To listview.SelectedItems.Count – 1
|
| items(i) = listview.SelectedItems(i)
|
| Next
|
| listview.DoDragDrop(New DataObject("ListViewItemData", _
|
| items), DragDropEffects.Move)
|
| End Sub
|
Zuerst wird ein Array vom Typ ListViewItem deklariert, das anschließend mit den ausgewählten Listenelementen aus der SelectedListViewItemCollection der Listenansicht gefüllt wird. Beim Aufruf der DoDragDrop-Methode müssen zuerst die an der Operation beteiligten Daten bekannt gegeben werden. Damit auch wirklich nur die dafür vorgesehene Listenansicht die Daten empfangen kann, spezifizieren wir ein eigenes DataObject. Dazu übergeben wir dem Konstruktor zuerst einen beliebigen Bezeichner für die zu verschiebenden Daten, anschließend die Daten selbst. Als Operation ist in diesem Beispiel nur das Verschieben vorgesehen.
Im Drag & Drop-Empfänger wird zuerst das Ereignis DragEnter ausgelöst. In diesem werden die gezogenen Daten einer Typuntersuchung unterzogen. Hier fragen wir nach dem Bezeichner, den wir im DataObject-Konstruktor genannt haben. Sind die Daten vom Typ ListView-ItemData, kann der Verschiebevorgang initialisiert werden.
| Private Sub listView_DragEnter(ByVal sender As Object, _
|
| ByVal e As DragEventArgs) _
|
| Handles ListView2.DragEnter, ListView1.DragEnter
|
| If e.Data.GetDataPresent("ListViewItemData") Then
|
| e.Effect = DragDropEffects.Move
|
| Else
|
| e.Effect = DragDropEffects.None
|
| End If
|
| End Sub
|
Dem Fallenlassen der gezogenen Daten und dem damit ausgelösten Ereignis DragDrop kommt jetzt nur noch die Aufgabe zu, den Empfänger mit den gezogenen Listenelementen zu füllen und diese gleichzeitig in der Quelle zu löschen.
| Private Sub listView_DragDrop(ByVal sender As Object, _
|
| ByVal e As DragEventArgs) _
|
| Handles ListView2.DragDrop, ListView1.DragDrop
|
| Dim listview As ListView = sender
|
| Dim items() As ListViewItem = e.Data.GetData("ListViewItemData")
|
| For i As Integer = 0 To items.Length – 1
|
| listview.Items.Add(items(i).Text)
|
| If (listview Is ListView1) Then
|
| ListView2.Items.Remove(ListView2.SelectedItems(0))
|
| Else
|
| ListView1.Items.Remove(ListView1.SelectedItems(0))
|
| End If
|
| Next
|
| End Sub
|
Den vollständigen Code zu diesem Beispiel finden Sie auf der Buch-CD unter: \Kapitel 24\DragAndDrop_Listen
Drag & Drop von Dateien
Das letzte Beispielprogramm soll Ihnen demonstrieren, wie Dateien gezogen werden – hier im Besonderen Dateien mit Textinhalt, aber grundsätzlich können Sie auf diese Weise mit jedem Dateityp verfahren. Die Dateien können beispielsweise aus dem Windows-Explorer in die Textbox der Form gezogen werden. Der Dateiinhalt wird dabei in der Textbox angezeigt.
Das Datenformat von Dateien, die an einer Drag & Drop-Operation teilnehmen, wird durch das Feld FileDrop der Klasse DataFormat beschrieben. Der Rückgabewert der Methode GetData ist dann die Zeichenfolge, die den Zugriffspfad auf die gezogene Datei beschreibt. Da es im Windows-Explorer auch möglich ist, mehrere Dateien zu ziehen, könnte es sich auch um ein Array handeln, das in ein Zeichenfolge-Array konvertiert werden muss.
Das Array wird in einer Schleife Element für Element durchlaufen. Nach einer Überprüfung der Dateierweiterung (es sind nur Dateien mit den Endungen TXT, INI und LOG zugelassen) wird die sich jeweils im Zugriff befindliche Datei geöffnet und im Fenster angezeigt.
| ' ---------------------------------------------------------
|
| ' Beispiel: ...\Kapitel 24\DragAndDrop_Dateien
|
| ' ---------------------------------------------------------
|
| Imports System.IO
|
| Public Class Form1
|
| Private Sub TextBox1_DragDrop(ByVal sender As Object, _
|
| ByVal e DragEventArgs) Handles TextBox1.DragDrop
|
| If e.Data.GetDataPresent(DataFormats.FileDrop) Then
|
| ' liefert in einem Array alle im Explorer ausgewählten Dateien
|
| Dim strFileName() As String = _
|
| e.Data.GetData(DataFormats.FileDrop)
|
| Dim sr As StreamReader
|
| ' alle ausgewählten Dateien in der Textbox anzeigen
|
| For i As Integer = 0 To strFileName.Length – 1
|
| Try
|
| ' nur TXT-, LOG- und INI-Dateien einlesen
|
| If (Path.GetExtension(strFileName(i)) = ".txt" _
|
| OrElse Path.GetExtension(strFileName(i)) _
|
| = ".log" OrElse Path.GetExtension(strFileName(i)) _
|
| = ".ini") Then
|
| sr = New StreamReader(strFileName(i))
|
| Else
|
| Continue For
|
| End If
|
| Catch ex As IOException
|
| MessageBox.Show(ex.Message)
|
| Return
|
| End Try
|
| TextBox1.Text &= New String("="c, 60) & vbCrLf
|
| TextBox1.Text &= "Datei: " & strFileName(i) & vbCrLf
|
| TextBox1.Text &= New String("="c, 60) & vbCrLf
|
| TextBox1.Text &= sr.ReadToEnd() & vbCrLf
|
| sr.Close()
|
| Next
|
| End If
|
| End Sub
|
| Private Sub textBox1_DragEnter(ByVal sender As Object, _
|
| ByVal e As DragEventArgs) Handles TextBox1.DragEnter
|
| If e.Data.GetDataPresent(DataFormats.FileDrop) Then
|
| e.Effect = DragDropEffects.Link
|
| Else
|
| e.Effect = DragDropEffects.None
|
| End If
|
| End Sub
|
| End Class
|
|